package com.geek.factory.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geek.factory.dto.*;
import com.geek.factory.entity.Material;
import com.geek.factory.entity.ProductionPlan;
import com.geek.factory.entity.ProductionPlanMaterial;
import com.geek.factory.mapper.*;
import com.geek.factory.service.IMaterialService;
import com.geek.factory.service.ProductionPlanService;
import com.geek.factory.service.configq.JobScheduler;
import lombok.RequiredArgsConstructor;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;


@Service
@RequiredArgsConstructor
public class ProductionPlanServiceImpl  extends ServiceImpl<ProductionPlanMapper, ProductionPlan> implements ProductionPlanService {

    @Autowired
    private final ProductionPlanMapper planMapper;
    @Autowired
    private final ProductionPlanMaterialMapper planMaterialMapper;

    @Autowired
    private final MaterialMapper materialMapper;
    @Autowired
    private IMaterialService materialService;

    private final JobScheduler jobScheduler;

    @Override
    @Transactional
    public void createPlan(CreateProductionPlanDTO dto) {
        // 校验和扣减库存（统一由 materialService 处理）
        materialService.deductMaterialStock(dto.getMaterial());

        // 创建生产计划
        ProductionPlan plan = new ProductionPlan();
        plan.setPlanCode(dto.getCode());
        plan.setProductId(dto.getProductId());
        plan.setProductLineId(dto.getProductLineId());
        plan.setQuantity(dto.getQuantity());
        plan.setPlanStartTime(dto.getPlanStartTime());
        plan.setCompleteTime(dto.getCompleteTime());
        plan.setStatus("0");
        plan.setIsInStock(0);
        plan.setCreateTime(LocalDateTime.now());
        planMapper.insert(plan);

        // 调度定时任务
        try {
            jobScheduler.scheduleProductionPlanCompletionJob(
                    plan.getId(),
                    dto.getProductId(),
                    java.sql.Timestamp.valueOf(dto.getCompleteTime())
            );
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }

        // 绑定生产计划和原料
        for (MaterialUsageDTO material : dto.getMaterial()) {
            ProductionPlanMaterial planMaterial = new ProductionPlanMaterial();
            planMaterial.setPlanId(plan.getId());
            planMaterial.setMaterialId(material.getMaterialId());
            planMaterial.setRequiredQuantity(material.getRequiredQuantity());
            planMaterial.setUnit(material.getUnit());
            planMaterial.setRemark(material.getRemark());
            planMaterialMapper.insert(planMaterial);
        }


    }

    @Override
    public void deletePlan(Long id) {
        planMapper.deleteById(id);
        planMaterialMapper.delete(new QueryWrapper<ProductionPlanMaterial>().eq("plan_id", id));
    }

    @Override
    public void updatePlan(ProductionPlan plan) {
        planMapper.updateById(plan);
    }

    @Override
    public ProductionPlan getPlanById(Long id) {
        return planMapper.selectById(id);
    }

    @Resource
    private ProductionPlanMapper productionPlanMapper;


    @Override
    public List<ProductionPlanDTO> getPlanListWithNamesPaged(String planCode, Long productId, String productLineId, String status, int offset, int size) {
        return productionPlanMapper.getPlanListWithNamesPaged(planCode, productId, productLineId, status, offset, size);
    }

    @Override
    public long countPlanListWithNames(String planCode, Long productId, String productLineId, String status) {
        return productionPlanMapper.countPlanListWithNames(planCode, productId, productLineId, status);
    }


    @Override
    public List<ProductionPlanMaterialDTO> getPlanMaterialDetails(Long planId) {
        // 查询该计划的所有原料消耗记录
        List<ProductionPlanMaterial> materials = planMaterialMapper.selectList(
                new QueryWrapper<ProductionPlanMaterial>().eq("plan_id", planId));

        List<ProductionPlanMaterialDTO> dtoList = new ArrayList<>();
        for (ProductionPlanMaterial ppm : materials) {
            ProductionPlanMaterialDTO dto = new ProductionPlanMaterialDTO();
            dto.setMaterialId(ppm.getMaterialId());
            dto.setRequiredQuantity(ppm.getRequiredQuantity());
            dto.setUnit(ppm.getUnit());
            dto.setRemark(ppm.getRemark());

            // 根据 materialId 查询原料名称
            Material material = materialMapper.selectById(ppm.getMaterialId());
            dto.setMaterialName(material != null ? material.getMaterialName() : "未知");

            dtoList.add(dto);
        }

        return dtoList;
    }


    @Override
    @Transactional
    public void updatePlan(UpdateProductionPlanDTO dto) {
        Long planId = dto.getId();
        if (planId == null) {
            throw new RuntimeException("计划ID不能为空");
        }

        // 1. 查询原计划的原料明细
        List<ProductionPlanMaterial> oldMaterials = planMaterialMapper.selectList(
                new QueryWrapper<ProductionPlanMaterial>().eq("plan_id", planId)
        );

        // 2. 还原旧原料库存（增加）
        for (ProductionPlanMaterial old : oldMaterials) {
            materialMapper.increaseQuantity(old.getMaterialId(), old.getRequiredQuantity().intValue());
        }

        // 3. 校验新原料库存是否足够
        for (MaterialUsageDTO material : dto.getMaterial()) {
            Integer stock = materialMapper.selectQuantityById(material.getMaterialId());
            if (stock == null || stock < material.getRequiredQuantity().intValue()) {
                throw new RuntimeException("原料库存不足，原料ID：" + material.getMaterialId());
            }
        }

        // 4. 扣减新原料库存
        for (MaterialUsageDTO material : dto.getMaterial()) {
            int affected = materialMapper.decreaseQuantity(
                    material.getMaterialId(),
                    material.getRequiredQuantity().intValue()
            );
            if (affected <= 0) {
                throw new RuntimeException("库存扣减失败，原料ID：" + material.getMaterialId());
            }
        }

        // 5. 更新计划主信息
        ProductionPlan updatedPlan = new ProductionPlan();
        BeanUtils.copyProperties(dto, updatedPlan);
        productionPlanMapper.updateById(updatedPlan);

        // 6. 删除旧原料明细
        planMaterialMapper.delete(new QueryWrapper<ProductionPlanMaterial>().eq("plan_id", planId));

        // 7. 插入新原料明细
        for (MaterialUsageDTO material : dto.getMaterial()) {
            ProductionPlanMaterial newItem = new ProductionPlanMaterial();
            newItem.setPlanId(planId);
            newItem.setMaterialId(material.getMaterialId());
            newItem.setRequiredQuantity(material.getRequiredQuantity());
            newItem.setUnit(material.getUnit());
            newItem.setRemark(material.getRemark());
            planMaterialMapper.insert(newItem);
        }
    }


    @Override
    public List<ProductionPlanMaterialDTO> getPlanMaterialDetailsByCode(String planCode) {
        Long planId = productionPlanMapper.getPlanIdByPlanCode(planCode);
        if (planId == null) {
            throw new IllegalArgumentException("该计划编号不存在: " + planCode);
        }
        return getPlanMaterialDetails(planId);

    }

    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ProductLineMapper productLineMapper;

    @Override
    public ProductionPlanDTO getPlanDetailById(Long id) {
        ProductionPlan plan = productionPlanMapper.selectById(id);
        if (plan == null) {
            return null;
        }

        String productName = null;
        String productLineName = null;

        if (plan.getProductId() != null) {
            productName = productMapper.selectById(plan.getProductId()).getName();
        }
        if (plan.getProductLineId() != null) {
            productLineName = productLineMapper.selectById(plan.getProductLineId()).getLineName();
        }

        ProductionPlanDTO dto = new ProductionPlanDTO();
        BeanUtils.copyProperties(plan, dto);
        dto.setProductName(productName);
        dto.setProductLineName(productLineName);

        return dto;


    }

}












